package com.jiexinyun.handler;

import com.jiexinyun.dto.response.AjaxResult;
import com.jiexinyun.exception.BusinessException;
import com.jiexinyun.exception.GlobalException;
import com.jiexinyun.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.sql.SQLException;

/**
 * 这种处理方式会返回前端网络码 200 ，exceptionHandler返回的ApiResponse会以json的格式展示给前端 类似ResponseBody的内容
 * 例如：还没产生
 * 目前暂定只处理 BusinessException 之后可能扩展
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(value = { BusinessException.class })
    @ResponseStatus(value = HttpStatus.OK)
    public AjaxResult businessExceptionHandler(HttpServletRequest req, BusinessException e) {
        log.error("url : {}", req.getRequestURI(), e);
        return AjaxResult.developerError(e.getMessage());
    }

    @ExceptionHandler(value = { ServiceException.class })
    @ResponseStatus(value = HttpStatus.OK)
    public AjaxResult serviceExceptionHandler(HttpServletRequest req, ServiceException e) {
        log.error("url : {}", req.getRequestURI(), e);
        return AjaxResult.developerError(e.getMessage());
    }

    @ExceptionHandler(value = { GlobalException.class })
    @ResponseStatus(value = HttpStatus.OK)
    public AjaxResult globalExceptionHandler(HttpServletRequest req, GlobalException e) {
        log.error("url : {}", req.getRequestURI(), e);
        return AjaxResult.developerError(e.getMessage());
    }

    @ExceptionHandler(value = { Exception.class })
    @ResponseStatus(value = HttpStatus.OK)
    public AjaxResult exceptionHandler(HttpServletRequest req, Exception e) {
        log.error("url : {}", req.getRequestURI(), e);
        return AjaxResult.developerError(e.getMessage());
    }

    // 处理请求体参数验证异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public AjaxResult handleValidationException(HttpServletRequest req, MethodArgumentNotValidException ex) {
        log.error("url : {}", req.getRequestURI(), ex);
        StringBuffer sb = new StringBuffer(200);
        sb.append("请求体参数验证异常：").append(req.getRequestURI()).append("\n");
        ex.getBindingResult().getFieldErrors().forEach(error ->
                sb.append(error.getField()).append(":").append(error.getDefaultMessage()));
        return AjaxResult.developerError(sb.toString());
    }

    // 处理路径参数验证异常
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(value = HttpStatus.OK)
    public AjaxResult handleConstraintViolationException(HttpServletRequest req, ConstraintViolationException ex) {
        log.error("url : {}", req.getRequestURI(), ex);
        StringBuffer sb = new StringBuffer(200);
        sb.append("路径参数验证异常：").append(req.getRequestURI()).append("\n");
        ex.getConstraintViolations().forEach(violation ->
            sb.append(violation.getPropertyPath().toString()).append(":").append(violation.getMessage()));
        return AjaxResult.developerError(sb.toString());
    }

    // 处理MyBatis系统异常
    @ExceptionHandler(MyBatisSystemException.class)
    public AjaxResult handleMyBatisSystemException(HttpServletRequest req, MyBatisSystemException ex) {
        log.error("url : {}", req.getRequestURI(), ex);
        Throwable cause = ex.getCause();
        if (cause instanceof SQLException) {
            return handleSQLException(req,(SQLException) cause);
        }
        return AjaxResult.developerError("MyBatis系统异常:\n"+ex.getMessage());
    }

    // 处理JDBC SQL异常
    @ExceptionHandler(SQLException.class)
    public AjaxResult handleSQLException(HttpServletRequest req, SQLException ex) {
        log.error("url : {}", req.getRequestURI(), ex);
        return AjaxResult.developerError("SQL异常:\n"+ex.getMessage());
    }

}
